<template>
	<view>
		<u-navbar :title="pageTitle" titleStyle="color:#fff;" :placeholder="true" leftIconColor="#fff" :autoBack="true" bgColor="rgba(0,0,0,0)">
			
		</u-navbar>
		
		<view class="scene_add">
			<!--  -->
			<view class="title">
				<view class="name">
					声音名称
				</view>
			</view>
			<u--input
				placeholder="请输入声音的名称"
				border="none"
				v-model="title"
				customStyle="background:#2C2C2C;padding:12rpx 20rpx;"
				placeholderStyle="color:#979797;"
				fontSize="26rpx"
				color="#fff"
			></u--input>
			
			<view class="title">
				<view class="name">
					训练音频
				</view>
			</view>
			
			<view v-if="step == 0" class="sound_file">
				<view class="item" @click="step = 1">
					<view class="name yellow">
						<text>录制自己的声音</text>
						<u-icon name="arrow-right" color="#F9BE01" size="28rpx"></u-icon>
					</view>
					<view class="text">
						<view>录制15~30秒语音</view>
						<view>音频必须仅含有一个人在说话，说话人发音及音质越清晰、复刻质量越高</view>
						<view>如需要复刻情绪韵律起伏较强的音频,请尽量输入表现力强的音频</view>
					</view>
				</view>
				<view class="item" @click="getWeixinFile">
					<view class="name green">
						<text>从微信聊天上传</text>
						<u-icon name="arrow-right" color="#00E16F" size="28rpx"></u-icon>
					</view>
					<view class="text">
						<view>格式要求：mp3、m4a、wav</view>
						<view>音频须非拼接而成，避免过于喧哗的背景音和噪音。</view>
						<view>如说话人喉音/声音底噪严重,则复刻音频喉音和底噪将会较为严重</view>
					</view>
				</view>
			</view>
		</view>
		
		<!-- step1 -->
		<view v-if="step == 1" class="step_title">
			<view class="name">
				STEP1 选择朗读文本
			</view>
			<view class="text">
				如果没想好录音时说什么，就挑一段模板文本吧
			</view>
		</view>
		
		<view v-if="step == 1" class="step_text">
			<u-scroll-list :indicator="false">
				<view v-for="(item, index) in readTextData" class="item" :class="textDataIndex == index?'hover':''" @click="clickTextData(index)" :key="index">
					<view class="name">
						{{item.title}}
					</view>
					<view class="text">
						{{item.content}}
					</view>
				</view>
			</u-scroll-list>
		</view>
		
		<!-- step2 -->
		<view v-if="step == 2">
			<view class="step_title">
				<view class="name">
					STEP2 开始录音
				</view>
				<view class="text">
					录音时需要保持音量大小、语速稳定、注意断句、避免口腔噪音(如口水声)、环境杂音、混响等情况。
				</view>
			</view>
			<view class="read_text">
				<view class="name">
					{{readTextData[textDataIndex].title}}
				</view>
				<view class="text">
					{{readTextData[textDataIndex].content}}
				</view>
			</view>
			
			<view v-if="!isRecording" class="read_play">
				<view class="btn" @tap="$u.throttle(recorderStart, 500)">
					<u-icon name="mic" color="#F9BE01" size="90rpx"></u-icon>
				</view>
				<view class="name">
					开始录音
				</view>
			</view>
			<view v-if="isRecording" class="read_end">
				<image class="ico" src="../static/img/ico_sound.png" mode="widthFix"></image>
				<view class="time">
					{{timerDisplay}}
				</view>
				<view class="btn" @tap="$u.throttle(recorderEnd, 500)">
					结束录音
				</view>
			</view>
		</view>
		
		<!-- step3 -->
		<view v-if="step == 3" class="step3_btn">
			<view class="item">
				<view class="btn_reload" @click="reUpload">
					<view class="bgff">
						<u-icon name="reload" color="#494949" size="56rpx" bold></u-icon>
					</view>
				</view>
				<view class="name">
					重新上传
				</view>
			</view>
			<view class="item">
				<view v-if="!isAudioPaly" class="btn_listen" @click="clickOnPlayAudio">
					<u-icon name="play-right-fill" color="#292D32" size="70rpx"></u-icon>
				</view>
				<view v-else class="btn_listen" @click="clickOnStopAudio">
					<u-icon name="pause" color="#292D32" size="50rpx"></u-icon>
				</view>
				
				<view class="name">
					试听
				</view>
			</view>
		</view>
		
		
		
		<view class="footer_none"></view>
		<view class="footer_yellow_btn disabled" v-if="step == 0">
			立即提交
		</view>
		
		<view class="footer_yellow_btn" v-if="step == 1" @click="step = 2">
			下一步
		</view>
		<view class="footer_yellow_btn disabled" v-if="step == 2">
			立即提交
		</view>
		
		<view class="footer_yellow_btn" v-if="step == 3&&!voiceId" @click="clickShowPromise">
			立即提交
		</view>
		
		<view v-if="step == 3&&voiceId">
			<view class="footer_yellow_btn" v-if="isEdit" @click="clickShowPromise">
				立即提交
			</view>
			<view v-else class="footer_yellow_btn disabled">
				立即提交
			</view>
		</view>
		
		
		<!-- 承诺 -->
		<u-popup :show="showPromise" :closeable="true" mode="center" bgColor="#484848" round="10rpx" :safeAreaInsetBottom="false" @close="closePromise" @open="openPromise">
			<view class="promise">
				<view class="title">
					{{instructions.title}}
				</view>
				<view class="text">
					{{instructions.content}}
				</view>
				<view class="btn" @click="clickAgree">
					我已知晓，同意
				</view>
			</view>
		</u-popup>
		
		<u-toast ref="uToast"></u-toast>
		
		
	</view>
</template>

<script>
	// 录音
	//const recorderManager = uni.getRecorderManager();
	// 音频
	//const innerAudioContext = uni.createInnerAudioContext();
	export default {
		data() {
			return {
				pageTitle:'创建我的声音',
				title:'',
				step: 0,
				textDataIndex:0,
				readTextData: [],
				showPromise: false,
				isPlay: false,
				userId: '',
				aliyunOssSign: {},
				voiceId: '',
				voiceType: 9,
				audioName: '',
				audioUrl:'',
				isAudioPaly: false,
				isRecorder: false,
				instructions:{},
				innerAudioContext:null,
				voiceInfo:{},
				isEdit:false,
				
				recorderManager: null, // 录音管理对象
				isRecording: false,    // 录音状态
				timer: null,           // 计时器
				recordingTime: 0,      // 录音时间（秒）
				timerDisplay: '00:00'  // 显示的录音时长
			}
		},
		onLoad(opt) {
			const that = this
			this.userId = uni.getStorageSync('userId');
			if(opt.step)
			{
				this.step = opt.step
			}
			if(opt.voiceId){
				this.voiceId = opt.voiceId
				this.pageTitle = '修改我的声音'
				this.getVoiceListInfo()
			}
			else{
				this.pageTitle = '创建我的声音'
			}
			if(opt.voiceType){
				this.voiceType = opt.voiceType
			}
			this.getReadTextExample()
			this.getAliyunOssSing()
			
			// 创建录音管理器
			this.recorderManager = uni.getRecorderManager();
			// 监听录音开始事件
			this.recorderManager.onStart(() => {
				console.log('录音开始');
				this.isRecording = true;
				this.startTimer();
			});
			// 监听录音停止事件
			this.recorderManager.onStop((res) => {
				console.log('录音停止，录音文件路径：', res.tempFilePath);
				if(res.duration < 5000){
					that.$refs.uToast.show({
						message: "录音时长限制：5秒 ～ 60秒"
					})
				}else{
					that.step = 3
					that.audioUrl = res.tempFilePath
					//that.audioName = that.audioUrl.substring(that.audioUrl.lastIndexOf('/') + 1);
					const timestamp = new Date().getTime();
					const randomNum = Math.floor(Math.random() * 10000);
					const fileName = timestamp + "_" + randomNum   + that.audioUrl.substring(that.audioUrl.lastIndexOf('.'));
					that.audioName = fileName
					console.log('音频名称---',fileName)
				}
				that.isRecording = false;
				that.stopTimer();
				// 停止后可以拿到录音文件路径 res.tempFilePath，进行后续处理
			});
			// 监听录音错误事件
			this.recorderManager.onError((err) => {
				console.log('录音出错：', err);
				this.isRecording = false;
				this.stopTimer();
				this.recorderManager = null;
				this.recorderManager = uni.getRecorderManager();
			});
			
			// 播放声音管理器
			this.innerAudioContext = uni.createInnerAudioContext();
			this.innerAudioContext.onPlay(() => {
				console.log('开始播放');
				this.isAudioPaly = true
			});
			this.innerAudioContext.onStop(() => {
				console.log('停止播放');
				this.isAudioPaly = false
			});
			this.innerAudioContext.onEnded(() => {
				console.log('自然播放结束');
				this.isAudioPaly = false
			});
			
		},
		methods: {
			// 获取声音详情
			getVoiceListInfo(){
				uni.$u.http.get('/api/speed_voice_list/'+this.userId +'?from=miniprogram&id='+this.voiceId).then(res => {
					console.log('我的声音详情-----',res.data.data)
					this.voiceInfo = res.data.data[0]
					this.title = this.voiceInfo.title
					this.audioUrl = this.voiceInfo.demo_url
				}).catch(err => {
					console.log(err)
				})
			},
			// 开始录音
			recorderStart(){
				this.recorderManager.start({sampleRate:44100,encodeBitRate:320000})
			},
			// 结束录音
			recorderEnd(){
				this.recorderManager.stop()
			},
			
			// 重新上传
			reUpload(){
				this.innerAudioContext.stop();
				this.isAudioPaly = false
				this.step = 0
				if(this.voiceId)
				{
					this.isEdit = true
				}
			},
			// 播放试听
			clickOnPlayAudio(){
				this.innerAudioContext.src = this.audioUrl;
				this.innerAudioContext.play();
			},
			// 暂停试听
			clickOnPauseAudio(){
				this.innerAudioContext.pause();
			},
			// 停止试听
			clickOnStopAudio(){
				this.innerAudioContext.stop();
			},
			// 获取阿里云上传请求参数
			getAliyunOssSing(){
				uni.$u.http.get('/api/aliyun_oss_sign/'+this.userId +'?from=miniprogram').then(res => {
					//console.log('阿里云请求参数-----',res.data.data)
					this.aliyunOssSign = res.data.data
				}).catch(err => {
					console.log(err)
				})
			},
			// 创建声音
			uploadVoiceAdd(){
				uni.showLoading({
					title: '提交中',
					mask: true
				});
				uni.$u.http.post('/api/speed_voice_add/'+this.userId +'?from=miniprogram',{
					title: this.title,
					audio_url: this.audioUrl,
					voice_type: this.voiceType
				}).then(res => {
					console.log('创建声音-----',res.data.data)
					uni.hideLoading();
				
					uni.navigateBack({
						delta: 1
					});
				}).catch(err => {
					console.log(err)
				})
			},
			// 重新训练声音
			uploadVoiceTrain(){
				uni.showLoading({
					title: '提交中',
					mask: true
				});
				uni.$u.http.post('/api/speed_voice_retrain/'+this.userId +'?from=miniprogram',{
					id: this.voiceId,
					audio_url: this.audioUrl,
					title: this.title
				}).then(res => {
					console.log('重新训练声音-----',res.data.data)
					uni.hideLoading()
					// uni.redirectTo({
					// 	url: '/soundPages/mySound/mySound'
					// })
					uni.navigateBack({
						delta: 1
					});
				}).catch(err => {
					console.log(err)
				})
			},
			// 上传文件到阿里云
			uploadFileAliyun(){
				const that = this
				uni.showLoading({
					title: '上传中',
					mask: true
				});
				uni.uploadFile({
					url: that.aliyunOssSign.host,
					filePath: that.audioUrl,
					name: 'file',
					formData: {
						key: that.aliyunOssSign.dir + that.audioName,
						policy: that.aliyunOssSign.policy,
						OSSAccessKeyId: that.aliyunOssSign.accessid,
						signature: that.aliyunOssSign.signature
					},
					success: (resa) => {
						console.log('上传------',resa)
						if(resa.statusCode == 204)
						{
							that.audioUrl = that.aliyunOssSign.host +'/'+ that.aliyunOssSign.dir + that.audioName
							uni.hideLoading();
							if(this.voiceId){
								this.uploadVoiceTrain()
							}
							else{
								that.uploadVoiceAdd()
							}
						}
						else{
							uni.hideLoading();
							that.$refs.uToast.show({
								message: "上传失败,请重新上传"
							})
						}
					}
				});
			},
			//从微信聊天上传文件
			getWeixinFile() {
				const that = this
				wx.chooseMessageFile({
					count: 1,
					type: 'file', //video， image， file
					extension:['mp3', 'wav', 'm4a','MP3', 'WAV', 'M4A'],
					success(res) {
						console.log(res)
						//const tempFilePath = res.tempFiles[0].path;
						//const fileName = tempFilePath.substring(tempFilePath.lastIndexOf('/') + 1);
						if(res.tempFiles[0].size > (10*1024*1024)){
							that.$refs.uToast.show({
								message: "音频不能大于10MB"
							})
							return
						}
						that.audioUrl = res.tempFiles[0].path;
						//that.audioName = that.audioUrl.substring(that.audioUrl.lastIndexOf('/') + 1);
						const timestamp = new Date().getTime();
						const randomNum = Math.floor(Math.random() * 10000);
						const fileName = timestamp + "_" + randomNum + that.audioUrl.substring(that.audioUrl.lastIndexOf('.'));
						that.audioName = fileName
						
						that.step = 3
					}
				})
			},
			clickShowPromise(){
				if(!this.title){
					this.$refs.uToast.show({
						message: "请填写声音名称"
					})
					return
				}
				this.showPromise = true
				this.innerAudioContext.stop();
			},
			clickAgree(){
				this.showPromise = false
				this.uploadFileAliyun()
				
			},
			// 语音朗读文案
			getReadTextExample(){
				uni.$u.http.get('/api/speed_txt_example/'+this.userId +'?from=miniprogram').then(res => {
					console.log('语音朗读文案-----',res.data.data)
					this.readTextData = res.data.data.example
					this.instructions = res.data.data.instructions
				}).catch(err => {
					console.log(err)
				})
			},
			openPromise() {
				// console.log('open');
			},
			closePromise() {
				this.showPromise = false
				// console.log('close');
			},
			clickTextData(index){
				this.textDataIndex = index
			},
			// 启动计时器
			startTimer() {
				this.recordingTime = 0;
				this.timer = setInterval(() => {
					this.recordingTime++;
					this.updateTimerDisplay();
				}, 1000); // 每隔 1 秒更新一次
			},
			// 停止计时器
			stopTimer() {
				clearInterval(this.timer);
				this.timerDisplay = '00:00'; // 重置计时器显示
			},
			// 更新计时器显示（格式：MM:SS）
			updateTimerDisplay() {
				let minutes = Math.floor(this.recordingTime / 60);
				let seconds = this.recordingTime % 60;
				this.timerDisplay = this.formatTime(minutes) + ':' + this.formatTime(seconds);
			},
			// 格式化时间为两位数
			formatTime(value) {
				return value < 10 ? '0' + value : value;
			}
		}
	}
</script>

<style lang="scss" scoped>
.promise{
	width: 560rpx;
	box-sizing: border-box;
	padding:0 30rpx 35rpx;
	.btn{
		height: 70rpx;
		border-radius: 35rpx;
		background: #F9BE01;
		line-height: 70rpx;
		text-align: center;
		color: #3D3D3D;
		font-size: 26rpx;
		font-weight: 600;
		margin-top: 25rpx;
	}
	.title{
		text-align: center;
		font-size: 26rpx;
		font-weight: normal;
		line-height: 40rpx;
		color: #FFFFFF;
		padding:25rpx 0 25rpx;
	}
	.text{
		font-size: 20rpx;
		font-weight: normal;
		line-height: 32rpx;
		color: #FFFFFF;
		text-align: justify;
		height: 600rpx;
		overflow-y: auto;
	}
}
.step3_btn{
	display: flex;
	align-items: center;
	justify-content: space-between;
	padding:60rpx 120rpx 0;
	.item{
		width: 180rpx;
		.btn_reload{
			width: 180rpx;
			height: 180rpx;
			border-radius: 50%;
			background: #494949;
			display: flex;
			align-items: center;
			justify-content: center;
			.bgff{
				background: #fff;
				width: 66rpx;
				height: 66rpx;
				border-radius: 10rpx;
				display: flex;
				align-items: center;
				justify-content: center;
			}
		}
		.btn_listen{
			width: 180rpx;
			height: 180rpx;
			border-radius: 50%;
			background: #F9BE01;
			display: flex;
			align-items: center;
			justify-content: center;
		}
		.name{
			text-align: center;
			font-size: 26rpx;
			font-weight: normal;
			line-height: 40rpx;
			color: #FFFFFF;
			padding-top: 30rpx;
		}
	}
}
.read_end{
	text-align: center;
	padding-top: 100rpx;
	.ico{
		display: block;
		width: 152rpx;
		height: 135rpx;
		margin: 0 auto;
	}
	.time{
		font-size: 26rpx;
		font-weight: normal;
		line-height: 40rpx;
		color: #fff;
		text-align: center;
		padding:30rpx 0 40rpx;
	}
	.btn{
		width: 580rpx;
		height: 70rpx;
		border-radius: 37rpx;
		background: #494949;
		font-size: 26rpx;
		font-weight: 500;
		line-height: 70rpx;
		color: #fff;
		margin: 0 auto;
	}
}
.read_play{
	display: flex;
	align-items: center;
	justify-content: center;
	flex-direction: column;
	padding-top: 100rpx;
	.btn{
		width: 200rpx;
		height: 200rpx;
		background: rgba(249, 190, 1, 0.1519);
		border-radius: 50%;
		box-sizing: border-box;
		border: 2rpx solid #F9BE01;
		display: flex;
		align-items: center;
		justify-content: center;
	}
	.name{
		padding-top: 20rpx;
		font-size: 26rpx;
		font-weight: normal;
		line-height: 40rpx;
		color: #FFFFFF;
	}
}
.read_text{
	margin: 30rpx 40rpx 0;
	border-radius: 10rpx;
	background: #2C2C2C;
	box-sizing: border-box;
	padding:30rpx 30rpx;
	.name{
		font-size: 26rpx;
		font-weight: normal;
		line-height: 40rpx;
		text-align: center;
	}
	.text{
		max-height: 160rpx;
		margin-top: 20rpx;
		font-size: 24rpx;
		font-weight: normal;
		line-height: 40rpx;
		text-align: justify;
		color: #A6A6A6;
		overflow-y: auto;
	}
}
.step_text{
	padding:30rpx 0;
	.item{
		flex-shrink: 0;
		width: 260rpx;
		
		border-radius: 10rpx;
		background: #2C2C2C;
		box-shadow: 2rpx 2rpx 30rpx 0rpx rgba(0, 0, 0, 0.05);
		box-sizing: border-box;
		padding:25rpx 30rpx;
		margin-left: 30rpx;
		border: 1rpx solid #2C2C2C;
		overflow: hidden;
		&:first-child{
			margin-left: 40rpx;
		}
		&.hover{
			border: 1rpx solid #F9BE01;
		}
		.name{
			font-size: 26rpx;
			font-weight: normal;
			line-height: 40rpx;
			text-align: center;
		}
		.text{
			margin-top: 12rpx;
			font-size: 20rpx;
			font-weight: normal;
			line-height: 32rpx;
			text-align: justify;
			color: #A6A6A6;
			overflow: hidden;
			display: -webkit-box;
			-webkit-box-orient: vertical;
			-webkit-line-clamp: 8;
			overflow: hidden;
			text-overflow: ellipsis;
		}
	}
}
.step_title{
	padding:0 40rpx;
	.name{
		font-weight: 600;
		font-size: 26rpx;
		line-height: 40rpx;
	}
	.text{
		font-size: 20rpx;
		line-height: 30rpx;
		color: #A6A6A6;
		margin-top: 10rpx;
	}
}
.scene_add{
	padding:0 40rpx;
	.sound_file{
		.item{
			height: 270rpx;
			border-radius: 15rpx;
			background: #393939;
			margin-bottom: 40rpx;
			display: flex;
			align-items: center;
			justify-content: center;
			flex-direction: column;
			.text{
				font-size: 20rpx;
				font-weight: normal;
				line-height: 30rpx;
				color: #A6A6A6;
				padding: 18rpx;
				text-align: center;
			}
			.name{
				display: flex;
				align-items: center;
				justify-content: center;
				&.yellow{
					color: #F9BE01;
				}
				&.green{
					color: #00E16F;
				}
				text{
					display: block;
					font-size: 26rpx;
					font-weight: 500;
					line-height: 40rpx;
					padding-right: 6rpx;
				}
			}
			
			
		}
	}
	.title{
		display: flex;
		align-items: center;
		padding:40rpx 0 20rpx;
		.text{
			color: #979797;
			font-size: 26rpx;
			line-height: 40rpx;
		}
		.name{
			font-size: 26rpx;
			font-weight: normal;
			line-height: 40rpx;
			color: #FFFFFF;
		}
		text{
			display: block;
			color: #FF1313;
			font-size: 26rpx;
			line-height: 40rpx;
		}
	}
}
.footer_none{
	width: 100%;
	height: 160rpx;
}
.footer_yellow_btn{
	position: fixed;
	left:40rpx;
	right: 0;
	bottom: 60rpx;
	width: 670rpx;
	height: 70rpx;
	border-radius: 35rpx;
	background: #F9BE01;
	line-height: 70rpx;
	text-align: center;
	font-size: 26rpx;
	color: #292D32;
	font-weight: 600;
	&.disabled{
		opacity: 0.3;
	}
}
</style>
